home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / share / pyshared / DistUpgrade / DistUpgradeAptCdrom.py < prev    next >
Text File  |  2009-11-02  |  12KB  |  289 lines

  1. # DistUpgradeAptCdrom.py 
  2. #  
  3. #  Copyright (c) 2008 Canonical
  4. #  
  5. #  Author: Michael Vogt <michael.vogt@ubuntu.com>
  6. #  This program is free software; you can redistribute it and/or 
  7. #  modify it under the terms of the GNU General Public License as 
  8. #  published by the Free Software Foundation; either version 2 of the
  9. #  License, or (at your option) any later version.
  10. #  This program is distributed in the hope that it will be useful,
  11. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. #  GNU General Public License for more details.
  14. #  You should have received a copy of the GNU General Public License
  15. #  along with this program; if not, write to the Free Software
  16. #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  17. #  USA
  18.  
  19. import re
  20. import os
  21. import apt
  22. import apt_pkg
  23. import logging
  24. import gzip
  25. import shutil
  26. import subprocess
  27. from gettext import gettext as _
  28.  
  29.  
  30. class AptCdromError(Exception):
  31.     " base exception for apt cdrom errors "
  32.     pass
  33.  
  34. class AptCdrom(object):
  35.     " represents a apt cdrom object "
  36.  
  37.     def __init__(self, view, path):
  38.         self.view = view
  39.         self.cdrompath = path
  40.         # the directories we found on disk with signatures, packages and i18n
  41.         self.packages = set()
  42.         self.signatures = set()
  43.         self.i18n = set()
  44.  
  45.     def restoreBackup(self, backup_ext):
  46.         " restore the backup copy of the cdroms.list file (*not* sources.list)! "
  47.         cdromstate = os.path.join(apt_pkg.Config.FindDir("Dir::State"),
  48.                                   apt_pkg.Config.Find("Dir::State::cdroms"))
  49.         if os.path.exists(cdromstate+backup_ext):
  50.             shutil.copy(cdromstate+backup_ext, cdromstate)
  51.         # mvo: we don't have to care about restoring the sources.list here because
  52.         #      aptsources will do this for us anyway
  53.         
  54.  
  55.     def _scanCD(self):
  56.         """ 
  57.         scan the CD for interessting files and return them as:
  58.         (packagesfiles, signaturefiles, i18nfiles)
  59.         """
  60.         packages = set()
  61.         signatures = set()
  62.         i18n = set()
  63.         for root, dirs, files in os.walk(self.cdrompath, topdown=True):
  64.             if (root.endswith("debian-installer") or 
  65.                 root.endswith("dist-upgrader")):
  66.                 del dirs[:]
  67.                 continue
  68.             elif  ".aptignr" in files:
  69.                 continue
  70.             elif "Packages" in files:
  71.                 packages.add(os.path.join(root,"Packages"))
  72.             elif "Packages.gz" in files:
  73.                 packages.add(os.path.join(root,"Packages.gz"))
  74.             elif "Sources" in files or "Sources.gz" in files:
  75.                 logging.error("Sources entry found in %s but not supported" % root)
  76.             elif "Release.gpg" in files:
  77.                 signatures.add(os.path.join(root,"Release.gpg"))
  78.             elif "i18n" in dirs:
  79.                 for f in os.listdir(os.path.join(root,"i18n")):
  80.                     i18n.add(os.path.join(root,"i18n",f))
  81.             # there is nothing under pool but deb packages (no
  82.             # indexfiles, so we skip that here
  83.             elif os.path.split(root)[1] == ("pool"):
  84.                 del dirs[:]
  85.         return (packages, signatures, i18n)
  86.  
  87.     def _writeDatabase(self):
  88.         " update apts cdrom.list "
  89.         dbfile = apt_pkg.Config.FindFile("Dir::State::cdroms")
  90.         cdrom = apt_pkg.GetCdrom()
  91.         (res,id)=cdrom.Ident(apt.progress.CdromProgress())
  92.         label = self._readDiskName()
  93.         out=open(dbfile,"a")
  94.         out.write('CD::%s "%s";\n' % (id, label))
  95.         out.write('CD::%s::Label "%s";\n' % (id, label))
  96.  
  97.     def _dropArch(self, packages):
  98.         " drop architectures that are not ours "
  99.         # create a copy
  100.         packages = set(packages)
  101.         # now go over the packagesdirs and drop stuff that is not
  102.         # our binary-$arch 
  103.         arch = apt_pkg.Config.Find("APT::Architecture")
  104.         for d in set(packages):
  105.             if "/binary-" in d and not arch in d:
  106.                 packages.remove(d)
  107.         return packages
  108.     
  109.     def _readDiskName(self):
  110.         diskname = None
  111.         info = os.path.join(self.cdrompath, ".disk","info")
  112.         if os.path.exists(info):
  113.             diskname = open(info).read()
  114.             for special in ('"',']','[','_'):
  115.                 diskname = diskname.replace(special,'_')
  116.         return diskname
  117.  
  118.     def _generateSourcesListLine(self, diskname, packages):
  119.         # see apts indexcopy.cc:364 for details
  120.         path = ""                                    
  121.         dist = ""
  122.         comps = []
  123.         for d in packages:
  124.             # match(1) is the path, match(2) the dist
  125.             # and match(3) the components
  126.             m = re.match("(.*)/dists/([^/]*)/(.*)/binary-*", d)
  127.             if not m:
  128.                 raise AptCdromError, _("Could not calculate sources.list entry")
  129.             path = m.group(1)
  130.             dist = m.group(2)
  131.             comps.append(m.group(3))
  132.         if not path or not comps:
  133.             return None
  134.         comps.sort()
  135.         pentry = "deb cdrom:[%s]/ %s %s" % (diskname, dist, " ".join(comps))
  136.         return pentry
  137.  
  138.     def _copyTranslations(self, translations, targetdir=None):
  139.         if not targetdir:
  140.             targetdir=apt_pkg.Config.FindDir("Dir::State::lists")
  141.         diskname = self._readDiskName()
  142.         for f in translations:
  143.             fname = apt_pkg.URItoFileName("cdrom:[%s]/%s" % (diskname,f[f.find("dists"):]))
  144.             outf = os.path.join(targetdir,os.path.splitext(fname)[0])
  145.             if f.endswith(".gz"):
  146.                 g=gzip.open(f)
  147.                 out=open(outf,"w")
  148.                 # uncompress in 64k chunks
  149.                 while True:
  150.                     s=g.read(64000)
  151.                     out.write(s)
  152.                     if s == "":
  153.                         break
  154.             else:
  155.                 shutil.copy(f,outf)
  156.         return True
  157.  
  158.     def _copyPackages(self, packages, targetdir=None):
  159.         if not targetdir:
  160.             targetdir=apt_pkg.Config.FindDir("Dir::State::lists")
  161.         # CopyPackages()
  162.         diskname = self._readDiskName()
  163.         for f in packages:
  164.             fname = apt_pkg.URItoFileName("cdrom:[%s]/%s" % (diskname,f[f.find("dists"):]))
  165.             outf = os.path.join(targetdir,os.path.splitext(fname)[0])
  166.             if f.endswith(".gz"):
  167.                 g=gzip.open(f)
  168.                 out=open(outf,"w")
  169.                 # uncompress in 64k chunks
  170.                 while True:
  171.                     s=g.read(64000)
  172.                     out.write(s)
  173.                     if s == "":
  174.                         break
  175.             else:
  176.                 shutil.copy(f,outf)
  177.         return True
  178.  
  179.     def _verifyRelease(self, signatures):
  180.         " verify the signatues and hashes "
  181.         gpgv = apt_pkg.Config.Find("Dir::Bin::gpg","/usr/bin/gpgv")
  182.         keyring = apt_pkg.Config.Find("Apt::GPGV::TrustedKeyring",
  183.                                       "/etc/apt/trusted.gpg")
  184.         for sig in signatures:
  185.             basepath = os.path.split(sig)[0]
  186.             # do gpg checking
  187.             releasef = os.path.splitext(sig)[0]
  188.             cmd = [gpgv,"--keyring",keyring,
  189.                    "--ignore-time-conflict",
  190.                    sig, releasef]
  191.             ret = subprocess.call(cmd)
  192.             if not (ret == 0):
  193.                 return False
  194.             # now do the hash sum checks
  195.             t=apt_pkg.ParseTagFile(open(releasef))
  196.             t.Step()
  197.             for entry in t.Section["SHA256"].split("\n"):
  198.                 (hash,size,name) = entry.split()
  199.                 f=os.path.join(basepath,name)
  200.                 if not os.path.exists(f):
  201.                     logging.info("ignoring missing '%s'" % f)
  202.                     continue
  203.                 sum = apt_pkg.sha256sum(open(f))
  204.                 if not (sum == hash):
  205.                     logging.error("hash sum mismatch expected %s but got %s" % (hash, sum))
  206.                     return False
  207.         return True
  208.  
  209.     def _copyRelease(self, signatures, targetdir=None):
  210.         " copy the release file "
  211.         if not targetdir:
  212.             targetdir=apt_pkg.Config.FindDir("Dir::State::lists")
  213.         diskname = self._readDiskName()
  214.         for sig in signatures:
  215.             releasef = os.path.splitext(sig)[0]
  216.             # copy both Release and Release.gpg
  217.             for f in (sig, releasef):
  218.                 fname = apt_pkg.URItoFileName("cdrom:[%s]/%s" % (diskname,f[f.find("dists"):]))
  219.                 shutil.copy(f,os.path.join(targetdir,fname))
  220.         return True
  221.  
  222.     def _doAdd(self):
  223.         " reimplement pkgCdrom::Add() in python "
  224.         # os.walk() will not follow symlinks so we don't need
  225.         # pkgCdrom::Score() and not dropRepeats() that deal with
  226.         # killing the links
  227.         (self.packages, self.signatures, self.i18n) = self._scanCD()
  228.         self.packages = self._dropArch(self.packages)
  229.         if len(self.packages) == 0:
  230.             logging.error("no useable indexes found on CD, wrong ARCH?")
  231.             raise AptCdromError, _("Unable to locate any package files, perhaps this is not a Ubuntu Disc or the wrong architecture?")
  232.  
  233.         # CopyAndVerify
  234.         if self._verifyRelease(self.signatures):
  235.             self._copyRelease(self.signatures)
  236.         
  237.         # copy the packages and translations
  238.         self._copyPackages(self.packages)
  239.         self._copyTranslations(self.i18n)
  240.  
  241.         # add CD to cdroms.list "database" and update sources.list
  242.         diskname = self._readDiskName()
  243.         if not diskname:
  244.             logging.error("no .disk/ directory found")
  245.             return False
  246.         debline = self._generateSourcesListLine(diskname, self.packages)
  247.         
  248.         # prepend to the sources.list
  249.         sourceslist=apt_pkg.Config.FindFile("Dir::Etc::sourcelist")
  250.         content=open(sourceslist).read()
  251.         open(sourceslist,"w").write("# added by the release upgrader\n%s\n%s" % (debline,content))
  252.         self._writeDatabase()
  253.  
  254.         return True
  255.  
  256.     def add(self, backup_ext=None):
  257.         " add a cdrom to apt's database "
  258.         logging.debug("AptCdrom.add() called with '%s'", self.cdrompath)
  259.         # do backup (if needed) of the cdroms.list file
  260.         if backup_ext:
  261.             cdromstate = os.path.join(apt_pkg.Config.FindDir("Dir::State"),
  262.                                       apt_pkg.Config.Find("Dir::State::cdroms"))
  263.             if os.path.exists(cdromstate):
  264.                 shutil.copy(cdromstate, cdromstate+backup_ext)
  265.         # do the actual work
  266.         apt_pkg.Config.Set("Acquire::cdrom::mount",self.cdrompath)
  267.         apt_pkg.Config.Set("APT::CDROM::NoMount","true")
  268.         # FIXME: add cdrom progress here for the view
  269.         progress = self.view.getCdromProgress()
  270.         try:
  271.             res = self._doAdd()
  272.         except (SystemError, AptCdromError), e:
  273.             logging.error("can't add cdrom: %s" % e)
  274.             self.view.error(_("Failed to add the CD"),
  275.                              _("There was a error adding the CD, the "
  276.                                "upgrade will abort. Please report this as "
  277.                                "a bug if this is a valid Ubuntu CD.\n\n"
  278.                                "The error message was:\n'%s'") % e)
  279.             return False
  280.         logging.debug("AptCdrom.add() returned: %s" % res)
  281.         return res
  282.  
  283.     def __nonzero__(self):
  284.         """ helper to use this as 'if cdrom:' """
  285.         return self.cdrompath is not None
  286.